package com.rocky.study.semaphore;

import java.util.concurrent.Semaphore;

/**
 * Oracle官方案例 --> Semaphore
 */
public class Pool {

    private static final int MAX_AVAILABLE = 100;

    private final Semaphore available = new Semaphore(MAX_AVAILABLE,true);

    protected Object[] items = new Object[MAX_AVAILABLE];

    protected boolean[] used = new boolean[MAX_AVAILABLE];

    /**
     * 获取一个空闲对象
     * 如果当前池中无空闲对象,则等待..直到有空闲对象为止
     * @return
     * @throws InterruptedException
     */
    public Object getItem() throws InterruptedException {
        available.acquire();
        return getNextAvailableItem();
    }

    /**
     * 归还对象到池中
     * @param x
     */
    public void putItem(Object x) {
        if (markAsUnused(x)) {
            available.release();
        }
    }

    /**
     * 获取池内一个空闲对象,获取成功则返回Object,失败返回 NULL
     * 成功后将对应的 used[i] = true
     * @return
     */
    private synchronized Object getNextAvailableItem() {
        for (int i = 0; i < MAX_AVAILABLE; ++i) {
            if (!used[i]) {
                used[i] = true;
                return items[i];
            }
        }
        return null;
    }

    /**
     * 归还对象到池中,归完成功返回 true
     * 归还失败:
     *      1.池中不存在该对象引用,返回false
     *      2.池中存在该对象引用,但该对象目前状态为空闲状态,也返回 false
     * @param item
     * @return
     */
    private synchronized boolean markAsUnused(Object item) {
        for (int i = 0; i < MAX_AVAILABLE; ++i) {
            if (item == items[i]) {
                if (used[i]) {
                    used[i] = false;
                    return true;
                } else
                    return false;
            }
        }
        return false;
    }
}
